SpringCloud Hystrix 服务降级
什么是服务降级
所谓降级,就是整体资源快不够用了,忍痛将某些服务先关掉,待度过难关,在开启回来。一般是从整体符合考虑,当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的 fallback 回调,返回一个缺省值,这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强。
配置环境
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- Hystrix-Dashboard -->
<!-- 注意这个不是必须的,它就是一个监控工具 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
基本配置降级使用
在启动类里加上这个 @EnableHystrix 注解
就是当要调用的服务挂了之后,默认返回一个托底数据防止当前服务也无法运行
@SpringBootApplication
@EnableFeignClients //开启Feign
@EnableEurekaClient
@EnableHystrix
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
然后就可以直接在这个方法上使用 @HystrixCommand 注解加上 fallback 的目标方法(其实这个 @HystrixCommand 可以写在 Service 层)
@GetMapping("/search/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack")
public Customer findById(@PathVariable Integer id) {
return searchClient.findById(id);
}
// findById 的降级方法,方法描述要和接口一致
public Customer findByIdFallBack(@PathVariable Integer id) {
return new Customer(-1, "", 0);
}
这里调用的 search 服务可以内部搞一个耗时操作,然后使用 JMeter 进行压力测试试试
private static final Object lock = new Object();
private static int count = 10;
public String payment(Integer id) {
int timeNumber = 500000;
// 可以使用 synchronized 来模拟这个耗时操作
for (int i = 0; i < timeNumber; i++) {
synchronized (lock) {
count++;
}
}
return id;
}
然后尝试一下两万的并发量

在 Service 层配置服务降级
除了像上面那样直接在 Controller 层配置服务降级,还可以在 Service 层(生产者服务)配置服务降级
生产者服务的 API
@Resource
private PaymentService paymentService;
@GetMapping(value = "/payment/hystrix/timeout/{id}")
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfoTimeout(id);
log.info("result:" + result);
return result;
}
调用的 Service 层
/**
* 这个 @HystrixCommand 报异常后如何处理: 一旦调用服务方法失败并抛出了错误信息后,
* 会自动调用 @HystrixCommand 标注好的 fallbackMethod 调用类中的指定方法
*/
@HystrixCommand(
fallbackMethod = "paymentInfoTimeOutHandler",
commandProperties = {
// 设置这个线程的超时时间是3s,3s内是正常的业务逻辑,超过3s调用 fallbackMethod 指定的方法进行处理
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfoTimeout(Integer id) {
int timeNumber = 5;
try {
TimeUnit.SECONDS.sleep(timeNumber); // 模拟超时错误
} catch (InterruptedException e) {
e.printStackTrace();
}
return
"当前调用的方法是:" + "paymentInfoTimeout" + "\n" +
"当前线程池:" + Thread.currentThread().getName() + "\n" +
"当前传入的 ID:" + id + "\n" +
"总耗时(秒):" + timeNumber;
}
public String paymentInfoTimeOutHandler(Integer id) {
return
"当前调用的方法是:" + "paymentInfoTimeout" + "\n" +
"当前线程池:" + Thread.currentThread().getName() + "\n" +
"当前传入的 ID:" + id + "\n" +
"系统繁忙,请稍后再试";
}